package cimage

import (
	"bytes"
	"gitee.com/theegg/go-brick/app/service/app"
	"github.com/nfnt/resize"
	"image"
	"image/draw"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io"
	"io/ioutil"
	"os"
)

// 类型判断
var GIF = []byte("GIF")
var JPG = []byte{0xff, 0xd8, 0xff}
var PNG = []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a}

// 类型定义
const (
	GifType = "image/gif"
	JpgType = "image/jpeg"
	PngType = "image/png"
)

var WaterMarkImageName = "mark_big.PNG"
var WaterMarkSmallImageName = "mark_small.PNG"

type CImage struct {
	image       image.Image
	resizeImage image.Image
	markImage   image.Image
}

// @title NewIm
// @description 初始化一个图片
func NewIm(imagePath string) (*CImage, error) {
	imFile, errImOpen := os.Open(imagePath)

	if errImOpen != nil {
		return nil, errImOpen
	}

	defer imFile.Close()

	imgType, errImType := GetImageTypeFromName(imagePath)

	if errImType != nil {
		return nil, app.NewError(errImType)
	}

	var iImage image.Image
	var errDecode error
	switch imgType {
	case GifType:
		iImage, errDecode = gif.Decode(imFile)
	case JpgType:
		iImage, errDecode = jpeg.Decode(imFile)
	case PngType:
		iImage, errDecode = png.Decode(imFile)
	default:
		iImage = nil
		errDecode = app.NewError("undefined type")
		return nil, errDecode
	}

	return &CImage{image: iImage}, nil
}

// @title Im
// @description
func (im *CImage) Im() image.Image {
	return im.image
}

// @title MarkIm
// @description
func (im *CImage) MarkIm() *CImage {
	return &CImage{image: im.markImage}
}

// @title ResizeIm
// @description
func (im *CImage) ResizeIm() *CImage {
	return &CImage{image: im.resizeImage}
}

// @title WaterMark
// @description 添加水印
// @params toImage  水印图片保存地址
// @params x 	　　	偏离右x
// @params y 	　　 偏离右y
func (im *CImage) WaterMark(watermark image.Image, x int, y int) *CImage {
	iImageBounds := im.image.Bounds()

	// 坐标偏移
	offset := image.Pt(iImageBounds.Dx()-watermark.Bounds().Dx()-x, iImageBounds.Dy()-watermark.Bounds().Dy()-y)

	// 画一张画布　大小和背景图一样大
	m := image.NewNRGBA(iImageBounds)

	// 把背景图放到画布上
	draw.Draw(m, iImageBounds, im.image, image.Pt(0, 0), draw.Src)

	// 把水印放到画布上
	draw.Draw(m, watermark.Bounds().Add(offset), watermark, image.Pt(0, 0), draw.Over)

	im.markImage = m

	return im
}

// @title Resize
// @description 图片改变尺寸
// @params width
// @params height
// @params quality
func (im *CImage) Resize(width int, height int, quality int) *CImage {
	if width == 0 || height == 0 {
		width = im.image.Bounds().Max.X
		height = im.image.Bounds().Max.Y
	}

	if quality == 0 {
		quality = 100
	}

	canvas := resize.Thumbnail(uint(width), uint(height), im.image, resize.Lanczos3)
	im.resizeImage = canvas
	return im
}

// @title SaveImage
// @description 保存图片
func (im *CImage) SaveImage(toPath string) error {
	toFile, error := os.Create(toPath)
	if error != nil {
		return error
	}

	defer toFile.Close()

	jpeg.Encode(toFile, im.image, &jpeg.Options{100})

	return nil
}

// @title GetImageTypeFromName
// @description 获取图片的后缀　通过文件地址
func GetImageTypeFromName(imgName string) (string, error) {
	fi, e := ioutil.ReadFile(imgName)
	if e != nil {
		panic(e)
	}

	return GetImageType(fi)
}

// @title GetImageTypeFromFile
// @description 获取图片的后缀　通过文件句柄
func GetImageTypeFromFile(file io.Reader) (string, error) {
	var chunks []byte
	buf := make([]byte, 1024)

	for {
		n, err := file.Read(buf)
		if err != nil && err != io.EOF {
			panic(err)
		}
		if 0 == n {
			break
		}
		chunks = append(chunks, buf...)
	}

	return GetImageType(chunks)
}

// @title GetImageType
// @description 获取图片
func GetImageType(fi []byte) (string, error) {
	var iType string

	if bytes.Equal(PNG, fi[0:8]) {
		iType = PngType
	}

	if bytes.Equal(GIF, fi[0:3]) {
		iType = GifType
	}

	if bytes.Equal(JPG, fi[0:3]) {
		iType = JpgType
	}

	if iType == "" {
		return iType, app.NewError("undefined type")
	} else {
		return iType, nil
	}
}
